﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Mapbox.Map;
using Mapbox.Unity.Map;
using Mapbox.Utils;
using System.Linq;
using Mapbox.Unity.MeshGeneration.Data;

public class RouteMap : MonoBehaviour
{
    public Material lineMaterial;

    private LineRenderer line;
    private LineRenderer Line
    {
        get
        {
            if (line == null)
            {
                line = new GameObject("Line").AddComponent<LineRenderer>();
                line.transform.SetParent(transform.Find("Other"), false);
                line.widthMultiplier = 2f;
                line.material = lineMaterial;
                line.startColor = new Color32(255, 84, 0, 255);
                line.endColor = new Color32(255, 195, 0, 255);
                line.useWorldSpace = false;
                line.transform.localPosition = -transform.position.y * Vector3.up;
            }
            return line;
        }
    }
    private AbstractMap currentMap;
    private bool hasSpawnCoute;

    private void OnEnable()
    {
        hasSpawnCoute = false;
        Spawn();
    }

    private void OnDisable()
    {
        RouteModel.Instance.Clear();
        ClearCache();
    }

    private void SetTileProviderState(bool isEnable)
    {
        GetComponent<CameraBoundsTileProvider>().enabled = isEnable;
    }

    private void ClearCache()
    {
        foreach (Transform item in transform.Find("Other"))
        {
            Destroy(item.gameObject);
        }

        line = null;
    }

    private void Spawn()
    {
        currentMap = GetComponent<AbstractMap>();
        SpawnMap(currentMap);
        FindObjectOfType<CameraManager>().TileVisibuffer = GetComponent<CameraBoundsTileProvider>().VisibleBuffer;
    }

    private void SpawnMap(AbstractMap map)
    {
        SetMapSideLength();
        Vector2d centerPoint = GetCenterPoint();
        if (centerPoint != default(Vector2d))
        {
            map.Initialize(centerPoint, 16);
            map.MapVisualizer.OnMapVisualizerStateChanged += UpdateMap;
        }
    }

    private void UpdateMap(ModuleState state)
    {
        if (state == ModuleState.Finished)
        {
            if (!hasSpawnCoute)
            {
                hasSpawnCoute = true;
                MapFinish();
                currentMap.MapVisualizer.OnMapVisualizerStateChanged -= UpdateMap;
            }
        }
        else if (state == ModuleState.Working)
        {
            StartCoroutine(Interval());
        }
    }

    private IEnumerator Interval()
    {
        yield return new WaitForSeconds(2);
        if (!hasSpawnCoute)
        {
            hasSpawnCoute = true;
            MapFinish();
            currentMap.MapVisualizer.OnMapVisualizerStateChanged -= UpdateMap;
        }
    }

    private void MapFinish()
    {
        SpawnPedestal();
        SpawnRouteLine();
    }

    private void SpawnPedestal()
    {
        GameObject Pedestal = Resources.Load("Prefab/Pedestal") as GameObject;
        GameObject temp;
        bool hasSpawn = false;
        foreach (Transform item in transform)
        {
            hasSpawn = false;
            if (item.name.Contains("Other"))
                continue;
            foreach (Transform child in item)
            {
                if (child.name.Contains("Pedestal"))
                {
                    hasSpawn = true;
                    break;
                }
            }
            if (!hasSpawn)
            {
                temp = Instantiate(Pedestal, item);
                temp.transform.localPosition = (-transform.position.y - 2 - temp.transform.localScale.y / 2) * Vector3.up;
            }
        }
    }

    private void DisableTile()
    {
        int count = RouteModel.Instance.RouteTileCache.Count;
        UnwrappedTileId maxTile = RouteModel.Instance.RouteTileCache[count - 1];
        UnwrappedTileId minTile = RouteModel.Instance.RouteTileCache[0];

        UnityTile tile;
        foreach (Transform item in transform)
        {
            tile = item.GetComponent<UnityTile>();
            if(tile != null)
            {
                if(tile.UnwrappedTileId.X>= minTile.X
                    && tile.UnwrappedTileId.X <= maxTile.X
                     && tile.UnwrappedTileId.Y >= minTile.Y
                      && tile.UnwrappedTileId.Y <= maxTile.Y)
                {
                    item.gameObject.SetActive(true);
                }
                else
                {
                    item.gameObject.SetActive(false);
                }
            }
        }
    }

    private Vector2d GetCenterPoint()
    {
        List<Vector2d> temp = RouteModel.Instance.RoutePointCache;
        double minX = temp[0].x;
        double maxX = temp[0].x;
        double minY = temp[0].y;
        double maxY = temp[0].y;
        for (int i = 1; i < temp.Count; i++)
        {
            if (minX > temp[i].x)
            {
                minX = temp[i].x;
            }
            if (maxX < temp[i].x)
            {
                maxX = temp[i].x;
            }
            if (minY > temp[i].y)
            {
                minY = temp[i].y;
            }
            if (maxY < temp[i].y)
            {
                maxY = temp[i].y;
            }
        }
        int count = RouteModel.Instance.RoutePointCache.Count;
        if (count > 0)
        {
            double offSetX = maxX - minX;
            double offSetY = maxY - minY;
            return new Vector2d(minX + offSetX * 0.5f, minY + offSetY * 0.5f);
        }
        return default(Vector2d);
    }

    private void SetMapSideLength()
    {
        int count = RouteModel.Instance.RouteTileCache.Count;
        if (count > 0)
        {
            UnwrappedTileId maxTile = RouteModel.Instance.RouteTileCache[count - 1];
            UnwrappedTileId minTile = RouteModel.Instance.RouteTileCache[0];
            int offSetX = maxTile.X - minTile.X;
            int offSetY = maxTile.Y - minTile.Y;
            int length = offSetX > offSetY ? offSetX : offSetY;
            length = length + 1;//显示地形的边长,单位是切片块数
            length = length % 2 == 0 ? length + 1 : length;//边长的数量必须为奇数
            CameraBoundsTileProvider tileProvider = GetComponent<CameraBoundsTileProvider>();
            tileProvider.VisibleBuffer = (length - 1) / 2;
        }
    }

    private void SpawnRouteLine()
    {
        StartCoroutine(RouteAppear(currentMap));
    }

    private IEnumerator RouteAppear(AbstractMap map)
    {
        Vector3[] points = GetPoints(map);

        SpawnStartPoint(points);

        for (int i = 0; i < points.Length; i++)
        {
            Line.positionCount = i + 1;
            Line.SetPosition(i, points[i]);
            yield return null;
            yield return null;
        }

        SpawnEndPoint(points);
    }

    private void SpawnStartPoint(Vector3[] points)
    {
        GameObject start = Resources.Load("Prefab/StartPoint") as GameObject;
        Instantiate(start, transform.Find("Other")).transform.position = points[0] + Vector3.up * 12.5f;
    }

    private void SpawnEndPoint(Vector3[] points)
    {
        GameObject end = Resources.Load("Prefab/EndPoint") as GameObject;
        Instantiate(end, transform.Find("Other")).transform.position = points[points.Length - 1] + Vector3.up * 12.5f;
    }

    private Vector3[] GetPoints(AbstractMap map)
    {
        Vector3[] points = new Vector3[RouteModel.Instance.RoutePointCache.Count];
        Vector3 temp;
        for (int i = 0; i < RouteModel.Instance.RoutePointCache.Count; i++)
        {
            //获取经纬度对应的世界坐标 
            temp = map.GeoToWorldPosition(RouteModel.Instance.RoutePointCache[i]);
            temp.y = 2;
            points[i] = temp;
        }
        return points;
    }
}
